home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / fish / 001-100 / 001-025 / 010 / iff / iffr.c < prev    next >
C/C++ Source or Header  |  1995-03-17  |  11KB  |  343 lines

  1. /*----------------------------------------------------------------------*
  2.  * IFFR.C  Support routines for reading IFF-85 files.          11/15/85
  3.  * (IFF is Interchange Format File.)
  4.  *
  5.  * By Jerry Morrison and Steve Shaw, Electronic Arts.
  6.  * This software is in the public domain.
  7.  *
  8.  * This version for the Commodore-Amiga computer.
  9.  *----------------------------------------------------------------------*/
  10.  
  11. #include "iff.h"
  12. /*  #include "DF1:iff/gio.h" */
  13. /*  #define OFFSET_BEGINNING OFFSET_BEGINING */
  14.  
  15. /**  Manx expects INTs as 16 bits,  This wont matter on LAttice ***/
  16. extern LONG Seek();
  17. extern LONG Read();
  18.  
  19. /* ---------- Read -----------------------------------------------------*/
  20.  
  21. extern LONG PutID(); /**  Added as a diagnostic aid, will remove later ***/
  22.  
  23. /* ---------- OpenRIFF --------------------------------------------------*/
  24. IFFP OpenRIFF(file0, new0, clientFrame)
  25.    BPTR file0;   GroupContext *new0;   ClientFrame *clientFrame; {
  26.     register BPTR file = file0;
  27.     register GroupContext *new = new0;
  28.     IFFP iffp = IFF_OKAY;
  29.  
  30.     new->parent       = NL;      /* "whole file" has no parent.*/
  31.     new->clientFrame  = clientFrame;
  32.     new->file         = file;
  33.     new->position     = 0;
  34.     new->ckHdr.ckID   = new->subtype    = NULL_CHUNK;
  35.     new->ckHdr.ckSize = new->bytesSoFar = 0;
  36.  
  37.     /* Set new->bound. AmigaDOS specific code.*/
  38.     if (file <= 0)   return(NO_FILE);
  39.     Seek(file, 0L, OFFSET_END);         /* Seek to end of file.*/
  40.     new->bound = Seek(file, 0L, OFFSET_CURRENT);   /* Pos'n == #bytes in file.*/
  41.     if (new->bound < 0)   return(DOS_ERROR);   /* DOS being absurd.*/
  42.     Seek(file, 0L, OFFSET_BEGINNING);      /* Go to file start.*/
  43.     /* Would just do this if Amiga DOS maintained fh_End: */
  44.     /* new->bound = (FileHandle *)BADDR(file)->fh_End; */
  45.  
  46.     if ( new->bound < (long)sizeof(ChunkHeader) )
  47.    iffp = NOT_IFF;
  48.     return(iffp);
  49.     }
  50.  
  51. /* ---------- OpenRGroup -----------------------------------------------*/
  52. IFFP OpenRGroup(parent0, new0)   GroupContext *parent0, *new0; {
  53.     register GroupContext *parent = parent0;
  54.     register GroupContext *new    = new0;
  55.     IFFP iffp = IFF_OKAY;
  56.  
  57.     new->parent       = parent;
  58.     new->clientFrame  = parent->clientFrame;
  59.     new->file         = parent->file;
  60.     new->position     = parent->position;
  61.     new->bound        = parent->position + ChunkMoreBytes(parent);
  62.     new->ckHdr.ckID   = new->subtype    = NULL_CHUNK;
  63.     new->ckHdr.ckSize = new->bytesSoFar = 0;
  64.  
  65.     if ( new->bound > parent->bound  ||  IS_ODD(new->bound) )
  66.    iffp = BAD_IFF;
  67.     return(iffp);
  68.     }
  69.  
  70. /* ---------- CloseRGroup -----------------------------------------------*/
  71. IFFP CloseRGroup(context)   GroupContext *context; {
  72.     register LONG position;
  73.  
  74.     if (context->parent == NL) {
  75.    }  /* Context for whole file.*/
  76.     else {
  77.    position = context->position;
  78.    context->parent->bytesSoFar += position - context->parent->position;
  79.    context->parent->position = position;
  80.    }
  81.     return(IFF_OKAY);
  82.     }
  83.  
  84. /* ---------- SkipFwd --------------------------------------------------*/
  85. /* Skip over bytes in a context. Won't go backwards.*/
  86. /* Updates context->position but not context->bytesSoFar.*/
  87. /* This implementation is AmigaDOS specific.*/
  88. IFFP SkipFwd(context, bytes)
  89.  GroupContext *context;
  90.  LONG bytes;
  91.  {
  92.     IFFP iffp = IFF_OKAY;
  93.  
  94.     if (bytes > 0) {
  95.       if (-1 == Seek(context->file, bytes, OFFSET_CURRENT))
  96.         iffp = BAD_IFF;   /* Ran out of bytes before chunk complete.*/
  97.    else
  98.        context->position += bytes;
  99.    }
  100.     return(iffp);
  101.     }
  102.  
  103. /* ---------- GetChunkHdr ----------------------------------------------*/
  104. ID GetChunkHdr(context0)
  105.  GroupContext *context0;
  106.  {
  107.     register GroupContext *context = context0;
  108.     register IFFP iffp;
  109.     LONG remaining;
  110.  
  111.     /* Skip remainder of previous chunk & padding. */
  112.     iffp = SkipFwd(context,
  113.         ChunkMoreBytes(context) + IS_ODD(context->ckHdr.ckSize));
  114.     CheckIFFP();
  115.  
  116.     /* Set up to read the new header. */
  117.     context->ckHdr.ckID = BAD_IFF;   /* Until we know it's okay, mark it BAD.*/
  118.     context->subtype    = NULL_CHUNK;
  119.     context->bytesSoFar = 0;
  120.  
  121.     /* Generate a psuedo-chunk if at end-of-context. */
  122.     remaining = context->bound - context->position;
  123.     if (remaining == 0 ) {
  124.         context->ckHdr.ckSize = 0;
  125.         context->ckHdr.ckID   = END_MARK;
  126.     }
  127.     /* BAD_IFF if not enough bytes in the context for a ChunkHeader.*/
  128.     else if ((long)sizeof(ChunkHeader) > remaining) {
  129.          context->ckHdr.ckSize = remaining;
  130.     }
  131.  
  132.     /* Read the chunk header (finally). */
  133.     else {
  134.         switch (Read(context->file,
  135.                  &context->ckHdr, (long)sizeof(ChunkHeader)))
  136.            {
  137.            case -1: return(context->ckHdr.ckID = DOS_ERROR);
  138.            case 0:  return(context->ckHdr.ckID = BAD_IFF);
  139.            }
  140.  
  141. /*** $$$ ***
  142.    PutID(context->ckHdr.ckID);
  143.    printf("\n");
  144.    printf("id = %lx\n", context->ckHdr.ckID);
  145. **/
  146.  
  147.    /* Check: Top level chunk must be LIST or FORM or CAT. */
  148.    if (context->parent == NL) {
  149.        if (context->ckHdr.ckID != FORM &&
  150.            context->ckHdr.ckID != LIST &&
  151.            context->ckHdr.ckID != CAT )
  152.            return(context->ckHdr.ckID = NOT_IFF);
  153.    }
  154.  
  155.    /* Update the context. */
  156.    context->position += (long)sizeof(ChunkHeader);
  157.    remaining         -= (long)sizeof(ChunkHeader);
  158.  
  159.    /* Non-positive ID values are illegal and used for error codes.*/
  160.    /* We could check for other illegal IDs...*/
  161.    if (context->ckHdr.ckID <= 0 )
  162.         context->ckHdr.ckID = BAD_IFF;
  163.  
  164.    /* Check: ckSize negative or larger than # bytes left in context? */
  165.    else if (context->ckHdr.ckSize < 0  ||
  166.        context->ckHdr.ckSize > remaining) {
  167.        context->ckHdr.ckSize = remaining;
  168.        context->ckHdr.ckID   = BAD_IFF;
  169.        }
  170.  
  171.    /* Automatically read the LIST, FORM, PROP, or CAT subtype ID */
  172.    else {
  173.        if (context->ckHdr.ckID == LIST ||
  174.            context->ckHdr.ckID == FORM ||
  175.            context->ckHdr.ckID == PROP ||
  176.            context->ckHdr.ckID == CAT) {
  177.            iffp = IFFReadBytes(context, (BYTE *)&context->subtype,
  178.                                (long)sizeof(ID));
  179.            if (iffp != IFF_OKAY )
  180.              context->ckHdr.ckID = iffp;
  181.         }
  182.      }
  183.    }
  184.    return(context->ckHdr.ckID);
  185.  }
  186.  
  187. /* ---------- IFFReadBytes ---------------------------------------------*/
  188. IFFP IFFReadBytes(context, buffer, nBytes)
  189.   GroupContext *context;
  190.   BYTE *buffer;
  191.   LONG nBytes;
  192.   {
  193.       register IFFP iffp = IFF_OKAY;
  194.  
  195.     if (nBytes < 0)
  196.        iffp = CLIENT_ERROR;
  197.  
  198.     else if (nBytes > ChunkMoreBytes(context))
  199.        iffp = SHORT_CHUNK;
  200.  
  201.     else if (nBytes > 0 )
  202.       switch ( Read(context->file, buffer, nBytes) ) {
  203.          case -1: {iffp = DOS_ERROR; break; }
  204.          case 0:  {iffp = BAD_IFF;   break; }
  205.          default: {
  206.                      context->position   += nBytes;
  207.                      context->bytesSoFar += nBytes;
  208.          }
  209.      }
  210.    return(iffp);
  211.   }
  212.  
  213. /* ---------- SkipGroup ------------------------------------------------*/
  214. IFFP SkipGroup(context)  GroupContext *context;  {
  215.     }   /* Nothing to do, thanks to GetChunkHdr */
  216.  
  217. /* ---------- ReadIFF --------------------------------------------------*/
  218. IFFP ReadIFF(file, clientFrame)
  219.  BPTR file;
  220.  ClientFrame *clientFrame;
  221.  {
  222.     /*CompilerBug register*/ IFFP iffp;
  223.     GroupContext context;
  224.  
  225.     iffp = OpenRIFF(file, &context);
  226.     context.clientFrame = clientFrame;
  227.  
  228.     if (iffp == IFF_OKAY) {
  229.        iffp = GetChunkHdr(&context);
  230.  
  231.        if (iffp == FORM)
  232.          iffp = (*clientFrame->getForm)(&context);
  233.  
  234.        else if (iffp == LIST)
  235.          iffp = (*clientFrame->getList)(&context);
  236.  
  237.        else if (iffp == CAT)
  238.          iffp = (*clientFrame->getCat)(&context);
  239.     }
  240.     CloseRGroup(&context);
  241.  
  242.     if (iffp > 0 )           /* Make sure we don't return an ID.*/
  243.         iffp = NOT_IFF;      /* GetChunkHdr should've caught this.*/
  244.     return(iffp);
  245.     }
  246.  
  247. /* ---------- ReadIList ------------------------------------------------*/
  248. IFFP ReadIList(parent, clientFrame)
  249.   GroupContext *parent;
  250.   ClientFrame *clientFrame;
  251.   {
  252.      GroupContext listContext;
  253.      IFFP iffp;
  254.      BOOL propOk = TRUE;
  255.  
  256.      iffp = OpenRGroup(parent, &listContext);
  257.      CheckIFFP();
  258.  
  259.     /* One special case test lets us handle CATs as well as LISTs.*/
  260.     if (parent->ckHdr.ckID == CAT)
  261.        propOk = FALSE;
  262.     else
  263.        listContext.clientFrame = clientFrame;
  264.  
  265.     do {
  266.         iffp = GetChunkHdr(&listContext);
  267.            if (iffp == PROP) {
  268.              if (propOk)
  269.                iffp = (*clientFrame->getProp)(&listContext);
  270.              else
  271.                iffp = BAD_IFF;
  272.            }
  273.            else if (iffp == FORM)
  274.               iffp = (*clientFrame->getForm)(&listContext);
  275.  
  276.            else if (iffp == LIST)
  277.               iffp = (*clientFrame->getList)(&listContext);
  278.  
  279.            else if (iffp == CAT)
  280.               iffp = (*clientFrame->getList)(&listContext);
  281.  
  282.        if (listContext.ckHdr.ckID != PROP)
  283.            propOk = FALSE;   /* No PROPs allowed after this point.*/
  284.    } while (iffp == IFF_OKAY);
  285.  
  286.     CloseRGroup(&listContext);
  287.  
  288.     if (iffp > 0 )   /* Only chunk types above are allowed in a LIST/CAT.*/
  289.        iffp = BAD_IFF;
  290.     return(iffp == END_MARK ? IFF_OKAY : iffp);
  291.     }
  292.  
  293. /* ---------- ReadICat -------------------------------------------------*/
  294. /* By special arrangement with the ReadIList implement'n, this is trivial.*/
  295. IFFP ReadICat(parent)  GroupContext *parent;  {
  296.     return( ReadIList(parent, NL) );
  297.     }
  298.  
  299. /* ---------- GetFChunkHdr ---------------------------------------------*/
  300. ID GetFChunkHdr(context)
  301.  GroupContext *context;
  302.  {
  303.     register ID id;
  304.  
  305.     id = GetChunkHdr(context);
  306.     if (id == PROP)
  307.        context->ckHdr.ckID = id = BAD_IFF;
  308.     return(id);
  309.     }
  310.  
  311. /* ---------- GetF1ChunkHdr ---------------------------------------------*/
  312. ID GetF1ChunkHdr(context)   GroupContext *context; {
  313.     register ID id;
  314.     register ClientFrame *clientFrame = context->clientFrame;
  315.  
  316.     id = GetChunkHdr(context);
  317.     if (id == PROP)
  318.        id = BAD_IFF;
  319.  
  320.     else if (id == FORM)
  321.        id = (*clientFrame->getForm)(context);
  322.  
  323.     else if (id == LIST)
  324.        id = (*clientFrame->getForm)(context);
  325.  
  326.     else if (id == CAT)
  327.        id = (*clientFrame->getCat)(context);
  328.  
  329.     return(context->ckHdr.ckID = id);
  330.   }
  331.  
  332. /* ---------- GetPChunkHdr ---------------------------------------------*/
  333. ID GetPChunkHdr(context)
  334.     GroupContext *context;
  335.     {
  336.     register ID id;
  337.  
  338.     id = GetChunkHdr(context);
  339.     if (id == LIST || id == FORM || id == PROP || id == CAT )
  340.        id = context->ckHdr.ckID = BAD_IFF;
  341.     return(id);
  342.     }
  343.